package com.cqc.jdk8.Jutil;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * java.util.ArrayList.subList(fromIndex,toIndex)
 * 1 subList(start,end)结果是java.util.ArrayList$SubList，不是 java.util.ArrayList
 * 2 subList(start,end)后，修改原集合,会导致并发修改异常， ConcurrentModificationException。因为是同一个数组索引，且SubList重写了增减方法
 * 3 对SubList进行增减，会导致 原集合的值
 * 4 subList(start,end)持有原集合的引用，导致原集合不能回回收，如果内存小，会导致OOM
 */
public class ArrayListTest {


    /**
     * ArrayList.subList(..) 返回类型是 java.util.ArrayList.SubList，不是 java.util.ArrayList
     */
    @Test
    public void subList1() {
        ArrayList<String> parentList = new ArrayList<String>() {{
            add("a");
            add("b");
            add("c");
        }};
        //返回类型是 java.util.ArrayList.SubList
        List<String> subList = parentList.subList(0, 2);
        //强转 java.util.ArrayList 报错
        ArrayList<String> subList2 = (ArrayList<String>) parentList.subList(0, 2);
    }

    /**
     * ArrayList.subList(..) 修改原集合会报错 ConcurrentModificationException
     */
    @Test
    public void subList2() {
        List<String> parentList = new ArrayList<String>() {{
            add("a");
            add("b");
            add("c");
        }};

        List<String> subList = parentList.subList(0, 2);
        System.out.println(subList);
        parentList.add("A");
        System.out.println(parentList);
        System.out.println(subList);//报错ConcurrentModificationException,debug发现执行到 list.add("A");变量subList就报错了
    }

    /**
     * ArrayList.subList(..) 修改SubList，就会影响原List数据，但不报错
     */
    @Test
    public void subList3() {
        ArrayList<String> parentList = new ArrayList<String>() {{
            add("a");
            add("b");
            add("c");
        }};
        //a,b
        List<String> subList = parentList.subList(0, 2);
        System.out.println(subList);
        subList.add("A");
        //a,b,A
        System.out.println(subList);
        //a,b,A,c
        System.out.println(parentList);
    }

    /**
     * -Xms20m -Xmx40m
     * java.lang.OutOfMemoryError: Java heap space
     */
    @Test
    public void subList4() {
        List resultList = new ArrayList<>();

        //lambada写法
//        IntStream.range(0, 1000).forEach(x -> {
//            List<Integer> collectList = IntStream.range(0, 100000)
//                    .boxed()
//                    .collect(Collectors.toList());
//            resultList.add(collectList.subList(0, 1));
//        });
        //普通写法
        for (int i = 0; i < 1000; i++) {
            List<Integer> list = IntStream.range(0, 100000)
                    .boxed()
                    .collect(Collectors.toList());
            //subList会一直持有原集合的引用,导致不能垃圾回收
            resultList.add(list.subList(0, 1));
        }
        System.out.println(resultList.size());
    }

    /**
     * List.toArray()修改list,不会影响到生成的array，因为内部是拷贝
     */
    @Test
    public void toArray() {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
            add("c");
        }};
        Object[] array = list.toArray();
        //arr和arr2数据相同
        String[] arr = new String[list.size()];
        String[] arr2 = list.toArray(arr);
        //操作list不影响toArray生成的数组；操作array，也不影响原list
        list.add("d");
        System.out.println(arr2);
        System.out.println(arr.equals(arr2));//true
        arr2[0] = "A";
        System.out.println(arr2);
    }

    /**
     * 会改变list1的数据，只保留交集
     */
    @Test
    public void retainAll() {
        List<String> list1 = new ArrayList<String>() {{
            add("a");
            add("b");
            add("c");
        }};
        List<String> list2 = new ArrayList<String>() {{
            add("a");
            add("d");
            add("c");
        }};
        boolean flag = list1.retainAll(list2);
        System.out.println(flag);
    }
}
